package com.yaorange.web;

import com.yaorange.entity.Customer;
import com.yaorange.entity.CustomerSource;
import com.yaorange.entity.Emp;
import com.yaorange.service.CustomerService;
import com.yaorange.service.CustomerSourceService;
import com.yaorange.service.EmpService;
import com.yaorange.utils.POICellUtils;
import com.yaorange.utils.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@RestController
@CrossOrigin
@RequestMapping("/market/import")
public class MarketImportController {


    @Resource
    private EmpService empService;

    @Resource
    private CustomerSourceService customerSourceService;

    @Resource
    private CustomerService customerService;




    //前端客户来源下拉列表回显用
    @GetMapping("/sources")
    public List<CustomerSource> getCustomerSourceList(){
        return customerSourceService.getList();
    }


    @PostMapping
    //文件上传处理
    // MultipartFile file:接收Spring底层解析器解析后的上传文件(底层会将文件格式转化为MultipartFile格式)
    // HttpServletRequest request:用于获取伴随文件上传的额外参数
    public Map<String,Object> importCustomer(@RequestParam MultipartFile file,
                                             HttpServletRequest request) throws IOException {


        //返回的消息对象
        Map<String, Object> msgMap = new HashMap<>();
        msgMap.put("status",30000);

        //如果没上传文件，则报错
        if(file.isEmpty()){
            msgMap.put("msg","请上传一份文件");
            return msgMap;
        }


        //通过POI读取上传文件数据
        //通过构造函数观察，POI可以直接通过输入流读取文件创建工作簿
        //也就是说不需要服务器先上传文件后再读取服务器的文件来创建工作簿，因为MultipartFile中就可以获取上传文件的输入流
        InputStream inputStream = file.getInputStream();
        Workbook workbook = null;
        try {
            //通过工厂类创建工作簿(使用工厂类的原因：根据文件版本选择HSSF或XSSF创建工作簿)
            workbook = WorkbookFactory.create(inputStream);
        } catch (InvalidFormatException e) {
            msgMap.put("msg","上传文件解析失败");
            return msgMap;
        }



        //--------------------------文件格式后端校验-------
        //通过获取工作簿表判断表中数据行数
        //获取第一个表
        Sheet sheetAt = workbook.getSheetAt(0);

        //1）校验上传数据格式（比如：是否存在标题行，标题行的列是否完整）
        //获取第一行(标题行)
        Row titleRow = sheetAt.getRow(0);

        //没有标题行
        if(titleRow == null){
            msgMap.put("msg","上传文件必须存在标题行");
            return msgMap;
        }

        //1.1)判断标题行的列数是否符合规则
        short lastCellNum = titleRow.getLastCellNum();
        if(lastCellNum < 3){
            msgMap.put("msg","上传文件数据列不符合要求");
            return msgMap;
        }

        //1.2)判断标题行的列顺序是否符合规则
        String cellValue1 = titleRow.getCell(0).getStringCellValue();
        if(!"客户姓名".equals(cellValue1.trim())){
            msgMap.put("msg","上传文件标题行第一列必须为客户姓名");
            return msgMap;
        }
        String cellValue2 = titleRow.getCell(1).getStringCellValue();
        if(!"手机号码".equals(cellValue2.trim())){
            msgMap.put("msg","上传文件标题行第二列必须为手机号码");
            return msgMap;
        }
        String cellValue3 = titleRow.getCell(2).getStringCellValue();
        if(!"备注".equals(cellValue3.trim())){
            msgMap.put("msg","上传文件标题行第一列必须为备注");
            return msgMap;
        }

        //2）校验文件的数据是否为空
        if(sheetAt.getLastRowNum() <= 1){
            //表示只有标题行，没有数据行
            msgMap.put("msg","上传文件没有数据");
            return msgMap;
        }
        //--------------------------文件格式后端校验-------


        //获取前端传入参数值
        String username = request.getParameter("username").trim();
        //通过username获取操作员工对象
        Emp emp=empService.getEmpByUserName(username);
        if(emp==null){
            msgMap.put("msg","未知的操作人员，请检查");
            return msgMap;
        }

        //获取前端传来的“导入分配类型”
        Integer addType = Integer.valueOf(request.getParameter("addType"));
        //获取前端传来的"客户来源"
        int customerSourceId = Integer.parseInt(request.getParameter("customerSourceId"));
        //获取前端传来的"客户名单名称"
        String customerRosterName = request.getParameter("customerRosterName");


        //准备用于存储上传文件对象,（保证上传文件中的客户电话号码唯一）
        //所以使用Map集合存储，key为客户电话（map中key是唯一的）
        Map<String, Customer> importCustomerMap = new HashMap<>();
        //循环读取上传文件中的客户数据
        for(Row row:sheetAt){
            //跳过标题行，从第二行开始读取
            if(row.getRowNum()>0){
                //创建一个客户
                Customer customer = new Customer();
                //客户电话(第二列)必定不为空
                String phone = POICellUtils.getStringCellValue(row.getCell(1));
                //去除空数据
                if(StringUtils.isEmpty(phone)){
                    //电话号码列为空
                    continue;
                }
                //客户姓名
                String name = POICellUtils.getStringCellValue(row.getCell(0));
                //客户备注
                String phoneRemark = POICellUtils.getStringCellValue(row.getCell(2));

                //给创建的客户赋予上面的属性
                customer.setPhone(phone);
                customer.setName(name);
                customer.setPhoneRemark(phoneRemark);

                //设置前端传入的默认参数和导入客户的默认参数
                // 前端传入参数
                customer.setAddType(addType);//录入客户类型（1表示批量导入，3表示批量导入到公共池）
                //客户默认状态为：0:刚录入,未分配
                if(addType == 3){
                    customer.setState(Customer.CustomerState.commonPool.ordinal());
                }
                customer.setCustomerSourceId(customerSourceId);//客户来源id
                customer.setCustomerRosterName(customerRosterName);//客户名单名称

                //默认参数
                customer.setAddPersonId(emp.getEmpId());//录入员工id
                customer.setAddPersonName(emp.getEmpName());//录入员工姓名

                //将准备好的客户添加到map,可以解决文件中重复电话问题(map的主键唯一性)
                importCustomerMap.put(phone,customer);
            }
        }

        //上传文件中客户列数据全为空(相当于前后两次上传的表中数据一模一样)
        if(importCustomerMap.size() == 0){
            msgMap.put("msg","本次导入，没有有效客户");
            return msgMap;
        }


        //以上已经完成上传文件读取组装为客户集合（也已经解决文件本身的重复数据问题）
        //但是还可能存在和数据库中客户电话重复问题
        //解决办法：通过组装的客户Map中的key(电话号码)去数据库中判断是否存在重复（返回重复的电话集合，重复电话是少数）

        //获取所有新增的客户（即不重复的）电话集合
        Set<String> importCustomerPhones = importCustomerMap.keySet();

        //在将上面的电话集合与数据库中的电话比对是否重复
        List<String> repeatPhones = customerService.getRepeatPhones(importCustomerPhones);

        //判断是否新增的客户电话全部都与数据库中的电话重复
        if(repeatPhones.size() == importCustomerPhones.size()){
            msgMap.put("msg","本次传入文件中的客户全部已存在，请检查文件");
            return msgMap;
        }
        //遍历重复电话集合删除Map中的客户数据
        for (String repeatPhone : repeatPhones) {
            importCustomerMap.remove(repeatPhone);//通过key删除map中的数据
        }

        //---到这importCustomerMap中存放就是需要批量新增到数据库的客户数据（绝对不重复的电话号码）
        //就可以调用方法批量新增客户了
        int rows = customerService.importList(importCustomerMap);
        if(rows > 0) {
            msgMap.put("status", 20000);
            msgMap.put("success", true);
            msgMap.put("msg", "客户录入成功，本次成功添加" + rows + "个客户，已存在客户" + (repeatPhones.size()) + "个客户");
            //可以扩展异步将上传文件备份到服务器/upload
        }else{
            msgMap.put("msg", "客户录入失败");
        }
        return msgMap;

    }


}
